package com.ict.ycwl.clustercalculate.service.Impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ict.ycwl.clustercalculate.mapper.AccumulationMapper;
import com.ict.ycwl.clustercalculate.mapper.StoreMapper;
import com.ict.ycwl.clustercalculate.pojo.*;
import com.ict.ycwl.clustercalculate.service.CalculateService;
import org.apache.commons.math3.ml.clustering.CentroidCluster;
import org.apache.commons.math3.ml.clustering.Clusterable;
import org.apache.commons.math3.ml.clustering.KMeansPlusPlusClusterer;
import org.apache.commons.math3.ml.distance.EuclideanDistance;
import org.apache.commons.math3.random.MersenneTwister;
import org.apache.commons.math3.random.RandomGenerator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;


/**
 * @author yuhuaame
 */
@Service
public class CalculateServiceImpl implements CalculateService {

    @Autowired
    private StoreMapper storeMapper;

    @Autowired
    private AccumulationMapper accumulationMapper;

    /**
     * 全部聚集区计算
     */
    @Override
    public void calculateAll() {
        List<String> strings = storeMapper.selectAllAreaName();

        for (String s : strings) {
            if (s.contains("铁龙") || s.contains("大桥") || s.contains("必背")) {
                calculate(s, 12, 1, 3);
            } else {
                calculate(s, 12, 1, 20);
            }
        }

    }

    /**
     * 用来进行聚集区计算
     */
    @Override
    public void calculate(String areaName, int storeNumber, int minNumOfCluster, int maxNumOfCluster) {
        //获取初始经纬度矩阵
        ArrayList<DoublePoint> lngLatMatrix = getOriginalLngLatMatrix(areaName);
        //结果List<CentroidCluster<DoublePoint>>数组。用于存储“聚类操作后生成的每个小List<CentroidCluster<DoublePoint>>”
        List<CentroidCluster<DoublePoint>> kmeansTempList = new ArrayList<>();
        //达标List<CentroidCluster<DoublePoint>>数组。用于存储“商铺个数符合要求的List<CentroidCluster<DoublePoint>>”
        List<CentroidCluster<DoublePoint>> finalList = new ArrayList<>();
        //簇心数组。用于存储“商铺个数符合要求的文件的簇心”
        List<double[]> clusterCenters = new ArrayList<>();

        while (true) {
            //用于统计“商铺个数在0到12之间的文件个数”
//            int flag = 0;

            int lenOfKmeansTempList = kmeansTempList.size();

            if (lenOfKmeansTempList == 0 && finalList.size() == 0) {
                //计算不同簇数对应的SSE，并把簇数和SSE分别保存在numberOfClusters和sse
                List<Double> sse = new ArrayList<>();
                List<Integer> numberOfClusters = new ArrayList<>();

                int minNumberOfClusters = minNumOfCluster;
                int maxNumberOfClusters = maxNumOfCluster;

                //尝试不同的簇数
                cycleOfSSE(minNumberOfClusters, maxNumberOfClusters, lngLatMatrix, sse, numberOfClusters);

                //计算SSE下降速度的变化率
                List<Double> changeRate = getChangeRate(sse);

                //找出变化率急剧下降的位置的横坐标
                int bestK = getBestK(numberOfClusters, changeRate);

                //得到分类结果
//                List<CentroidCluster<DoublePoint>> bestClusters = myKmeans(bestK, 10, 0, lngLatMatrix);
                List<CentroidCluster<DoublePoint>> bestClusters = myKmeans(bestK, 30, 0, lngLatMatrix);

                splitClusterResultEntry(storeNumber, bestK, bestClusters, clusterCenters, kmeansTempList, finalList);
            } else {
                for (int i = 0; i < lenOfKmeansTempList; i++) {
                    //取kmeansTempList里的第一个元素，也就是第一个小聚集区
                    CentroidCluster<DoublePoint> firstCentroidCluster = kmeansTempList.get(0);
                    //重新获取当前小聚集区的lngLatMatrix
                    lngLatMatrix = getLngLatMatrix(firstCentroidCluster);

                    //如果当前小聚集区的长度小于12，即聚集区包含的商铺个数在0到12之间，则跳过
                    if (firstCentroidCluster.getPoints().size() <= storeNumber) {
//                        flag += 1;
                        //将当前的小聚集区加到finalList里
                        finalList.add(firstCentroidCluster);
                        //删除当前循环的小聚集区，这样下一次循环的第一个小聚集区就不是当前这个了
                        kmeansTempList.remove(firstCentroidCluster);

                    } else if (firstCentroidCluster.getPoints().size() <= (2 * storeNumber - 1)) {
                        //得到当前小聚集区的分类结果
//                        List<CentroidCluster<DoublePoint>> sonClusters = myKmeans(2, 10, 0, lngLatMatrix);
                        List<CentroidCluster<DoublePoint>> sonClusters = myKmeans(2, 30, 0, lngLatMatrix);

                        //对于这种if情况的分类结果，要进行当前小聚集区的子聚集区判断
                        //如果子聚集区的元素全部一样，那么就表明，当前小聚集区里面所有商铺的经纬度都一样
                        int repeatIndex = isExistRepeat(sonClusters);
                        if (repeatIndex != -1) {
                            //直接将这个含有重复元素的子聚集区保存到finalList里
                            finalList.add(sonClusters.get(repeatIndex));
                            //因为都一样，所以直接取第一个商铺的经纬度来做这个小聚集区的簇心，并加到clusterCenters里
                            clusterCenters.add(sonClusters.get(repeatIndex).getPoints().get(0).getPoint());

                            kmeansTempList.remove(firstCentroidCluster);

                            continue;

                        } else {
                            //否则必有两个元素不重复的子聚集区
                            splitClusterResultEntry(storeNumber, 2, sonClusters, clusterCenters, kmeansTempList, finalList);
                        }

                        kmeansTempList.remove(firstCentroidCluster);
                    } else {
                        //计算不同簇数对应的SSE，并把簇数和SSE分别保存在numberOfClusters和sse
                        List<Double> sse = new ArrayList<>();
                        List<Integer> numberOfClusters = new ArrayList<>();

                        int minNumberOfClusters = minNumOfCluster;
                        int maxNumberOfClusters = maxNumOfCluster;

                        //尝试不同的簇数
                        cycleOfSSE(minNumberOfClusters, maxNumberOfClusters, lngLatMatrix, sse, numberOfClusters);

                        //计算SSE下降速度的变化率
                        List<Double> changeRate = getChangeRate(sse);

                        //找出变化率急剧下降的位置的横坐标
                        int bestK = getBestK(numberOfClusters, changeRate);

                        //得到分类结果
//                        List<CentroidCluster<DoublePoint>> bestClusters = myKmeans(bestK, 10, 0, lngLatMatrix);
                        List<CentroidCluster<DoublePoint>> bestClusters = myKmeans(bestK, 30, 0, lngLatMatrix);

                        int repeatIndex = isExistRepeat(bestClusters);

                        if (repeatIndex != -1) {
                            finalList.add(bestClusters.get(repeatIndex));

                            clusterCenters.add(bestClusters.get(repeatIndex).getPoints().get(0).getPoint());

                            kmeansTempList.remove(firstCentroidCluster);

                            continue;
                        } else {
                            splitClusterResultEntry(storeNumber, bestK, bestClusters, clusterCenters, kmeansTempList, finalList);
                        }

                        kmeansTempList.remove(firstCentroidCluster);
                    }
                }
            }

            lenOfKmeansTempList = kmeansTempList.size();

            if (lenOfKmeansTempList == 0 && finalList.size() != 0) {
                break;
            }
        }

        if (accumulationMapper.selectAll(areaName) != 0) {
            accumulationMapper.updateIsDelete(areaName);
        }

        //添加聚集区到数据库
//        for (double[] d : clusterCenters) {
//            Accumulation accumulation = new Accumulation();
//            accumulation.setAreaName(areaName);
//            accumulation.setLongitude(d[0]);
//            accumulation.setLatitude(d[1]);
//            accumulationMapper.insert(accumulation);
//        }
        int areaNameNumber = 1;
        for (int i = 0; i < clusterCenters.size(); i++) {
            double[] d = clusterCenters.get(i);
            Accumulation accumulation = new Accumulation();
            accumulation.setAreaName(areaName);
            accumulation.setLongitude(d[0]);
            accumulation.setLatitude(d[1]);
            accumulation.setAccumulationName(areaName + areaNameNumber++);

            QueryWrapper<Store> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("longitude", d[0]).eq("latitude", d[1]);
            //用selectList是为了应对多个商铺的经纬度都是一样的错误情况
            List<Store> stores = storeMapper.selectList(queryWrapper);
            accumulation.setAccumulationAddress(stores.get(0).getStoreAddress());
            accumulation.setAreaId(stores.get(0).getAreaId());
            accumulation.setRouteId(stores.get(0).getRouteId());

            accumulationMapper.insert(accumulation);
        }

        //更新商铺的accumulation_id字段
        for (int i = 0; i < clusterCenters.size(); i++) {
            Long aId = accumulationMapper.selectIdByLonAndLat(clusterCenters.get(i)[0], clusterCenters.get(i)[1]);
            List<DoublePoint> points = finalList.get(i).getPoints();
            for (DoublePoint dp : points) {
                storeMapper.updateAccumulationIdByLonAndLat(aId, dp.getPoint()[0], dp.getPoint()[1]);
            }
        }

        lngLatMatrix = getRemainingLngLatMatrix(areaName);
        while(lngLatMatrix.size() != 0){
            //结果List<CentroidCluster<DoublePoint>>数组。用于存储“聚类操作后生成的每个小List<CentroidCluster<DoublePoint>>”
            kmeansTempList = new ArrayList<>();
            //达标List<CentroidCluster<DoublePoint>>数组。用于存储“商铺个数符合要求的List<CentroidCluster<DoublePoint>>”
            finalList = new ArrayList<>();
            //簇心数组。用于存储“商铺个数符合要求的文件的簇心”
            clusterCenters = new ArrayList<>();

            while (true) {
                //用于统计“商铺个数在0到12之间的文件个数”
//            int flag = 0;

                int lenOfKmeansTempList = kmeansTempList.size();

                if (lenOfKmeansTempList == 0 && finalList.size() == 0) {
                    //计算不同簇数对应的SSE，并把簇数和SSE分别保存在numberOfClusters和sse
                    List<Double> sse = new ArrayList<>();
                    List<Integer> numberOfClusters = new ArrayList<>();

                    int minNumberOfClusters = minNumOfCluster;
                    int maxNumberOfClusters = maxNumOfCluster;

                    //尝试不同的簇数
                    cycleOfSSE(minNumberOfClusters, maxNumberOfClusters, lngLatMatrix, sse, numberOfClusters);

                    //计算SSE下降速度的变化率
                    List<Double> changeRate = getChangeRate(sse);

                    //找出变化率急剧下降的位置的横坐标
                    int bestK = getBestK(numberOfClusters, changeRate);

                    //得到分类结果
//                List<CentroidCluster<DoublePoint>> bestClusters = myKmeans(bestK, 10, 0, lngLatMatrix);
                    List<CentroidCluster<DoublePoint>> bestClusters = myKmeans(bestK, 30, 0, lngLatMatrix);

                    splitClusterResultEntry(storeNumber, bestK, bestClusters, clusterCenters, kmeansTempList, finalList);
                } else {
                    for (int i = 0; i < lenOfKmeansTempList; i++) {
                        //取kmeansTempList里的第一个元素，也就是第一个小聚集区
                        CentroidCluster<DoublePoint> firstCentroidCluster = kmeansTempList.get(0);
                        //重新获取当前小聚集区的lngLatMatrix
                        lngLatMatrix = getLngLatMatrix(firstCentroidCluster);

                        //如果当前小聚集区的长度小于12，即聚集区包含的商铺个数在0到12之间，则跳过
                        if (firstCentroidCluster.getPoints().size() <= storeNumber) {
//                        flag += 1;
                            //将当前的小聚集区加到finalList里
                            finalList.add(firstCentroidCluster);
                            //删除当前循环的小聚集区，这样下一次循环的第一个小聚集区就不是当前这个了
                            kmeansTempList.remove(firstCentroidCluster);

                        } else if (firstCentroidCluster.getPoints().size() <= (2 * storeNumber - 1)) {
                            //得到当前小聚集区的分类结果
//                        List<CentroidCluster<DoublePoint>> sonClusters = myKmeans(2, 10, 0, lngLatMatrix);
                            List<CentroidCluster<DoublePoint>> sonClusters = myKmeans(2, 30, 0, lngLatMatrix);

                            //对于这种if情况的分类结果，要进行当前小聚集区的子聚集区判断
                            //如果子聚集区的元素全部一样，那么就表明，当前小聚集区里面所有商铺的经纬度都一样
                            int repeatIndex = isExistRepeat(sonClusters);
                            if (repeatIndex != -1) {
                                //直接将这个含有重复元素的子聚集区保存到finalList里
                                finalList.add(sonClusters.get(repeatIndex));
                                //因为都一样，所以直接取第一个商铺的经纬度来做这个小聚集区的簇心，并加到clusterCenters里
                                clusterCenters.add(sonClusters.get(repeatIndex).getPoints().get(0).getPoint());

                                kmeansTempList.remove(firstCentroidCluster);

                                continue;

                            } else {
                                //否则必有两个元素不重复的子聚集区
                                splitClusterResultEntry(storeNumber, 2, sonClusters, clusterCenters, kmeansTempList, finalList);
                            }

                            kmeansTempList.remove(firstCentroidCluster);
                        } else {
                            //计算不同簇数对应的SSE，并把簇数和SSE分别保存在numberOfClusters和sse
                            List<Double> sse = new ArrayList<>();
                            List<Integer> numberOfClusters = new ArrayList<>();

                            int minNumberOfClusters = minNumOfCluster;
                            int maxNumberOfClusters = maxNumOfCluster;

                            //尝试不同的簇数
                            cycleOfSSE(minNumberOfClusters, maxNumberOfClusters, lngLatMatrix, sse, numberOfClusters);

                            //计算SSE下降速度的变化率
                            List<Double> changeRate = getChangeRate(sse);

                            //找出变化率急剧下降的位置的横坐标
                            int bestK = getBestK(numberOfClusters, changeRate);

                            //得到分类结果
//                        List<CentroidCluster<DoublePoint>> bestClusters = myKmeans(bestK, 10, 0, lngLatMatrix);
                            List<CentroidCluster<DoublePoint>> bestClusters = myKmeans(bestK, 30, 0, lngLatMatrix);

                            int repeatIndex = isExistRepeat(bestClusters);

                            if (repeatIndex != -1) {
                                finalList.add(bestClusters.get(repeatIndex));

                                clusterCenters.add(bestClusters.get(repeatIndex).getPoints().get(0).getPoint());

                                kmeansTempList.remove(firstCentroidCluster);

                                continue;
                            } else {
                                splitClusterResultEntry(storeNumber, bestK, bestClusters, clusterCenters, kmeansTempList, finalList);
                            }

                            kmeansTempList.remove(firstCentroidCluster);
                        }
                    }
                }

                lenOfKmeansTempList = kmeansTempList.size();

                if (lenOfKmeansTempList == 0 && finalList.size() != 0) {
                    break;
                }
            }

            for (int i = 0; i < clusterCenters.size(); i++) {
                double[] d = clusterCenters.get(i);
                Accumulation accumulation = new Accumulation();
                accumulation.setAreaName(areaName);
                accumulation.setLongitude(d[0]);
                accumulation.setLatitude(d[1]);
                accumulation.setAccumulationName(areaName + areaNameNumber++);

                QueryWrapper<Store> queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("longitude", d[0]).eq("latitude", d[1]);
                //用selectList是为了应对多个商铺的经纬度都是一样的错误情况
                List<Store> stores = storeMapper.selectList(queryWrapper);
                accumulation.setAccumulationAddress(stores.get(0).getStoreAddress());
                accumulation.setAreaId(stores.get(0).getAreaId());
                accumulation.setRouteId(stores.get(0).getRouteId());

                accumulationMapper.insert(accumulation);
            }

            //更新商铺的accumulation_id字段
            for (int i = 0; i < clusterCenters.size(); i++) {
                Long aId = accumulationMapper.selectIdByLonAndLat(clusterCenters.get(i)[0], clusterCenters.get(i)[1]);
                List<DoublePoint> points = finalList.get(i).getPoints();
                for (DoublePoint dp : points) {
                    storeMapper.updateAccumulationIdByLonAndLat(aId, dp.getPoint()[0], dp.getPoint()[1]);
                }
            }

            lngLatMatrix = getRemainingLngLatMatrix(areaName);
        }
    }


    /**
     * 获取初始经纬度矩阵lngLatMatrix
     */
    private ArrayList<DoublePoint> getRemainingLngLatMatrix(String areaName) {
        List<LngAndLat> lngAndLats = storeMapper.selectRemainingLngLat(areaName);

        //过滤空值并获取经纬度信息，将经纬度信息存到lngLatMatrix中
        ArrayList<DoublePoint> lngLatMatrix = new ArrayList<>();

        for (LngAndLat ll : lngAndLats) {
            double[] doubles = {ll.getLongitude(), ll.getLatitude()};
            DoublePoint dp = new DoublePoint(doubles);
            lngLatMatrix.add(dp);
        }

        return lngLatMatrix;
    }

    /**
     * 获取初始经纬度矩阵lngLatMatrix
     */
    private ArrayList<DoublePoint> getOriginalLngLatMatrix(String areaName) {
        List<LngAndLat> lngAndLats = storeMapper.selectCoordinatesByAreaName(areaName);

        //过滤空值并获取经纬度信息，将经纬度信息存到lngLatMatrix中
        ArrayList<DoublePoint> lngLatMatrix = new ArrayList<>();

        for (LngAndLat ll : lngAndLats) {
            double[] doubles = {ll.getLongitude(), ll.getLatitude()};
            DoublePoint dp = new DoublePoint(doubles);
            lngLatMatrix.add(dp);
        }

        return lngLatMatrix;
    }

    /**
     * 尝试不同的簇数，记录每次分类的sse值
     */
    private void cycleOfSSE(int minNumberOfClusters, int maxNumberOfClusters, ArrayList<DoublePoint> lngLatMatrix, List<Double> sse, List<Integer> numberOfClusters) {
        if (lngLatMatrix.size() < maxNumberOfClusters) {
            maxNumberOfClusters = lngLatMatrix.size();
        }

        for (int k = minNumberOfClusters; k < maxNumberOfClusters; k++) {
            //k 是要形成的簇的数量（即聚类的簇数）。
            //-1 表示算法将尝试找到最佳的簇数，这意味着它将考虑从 k 到 maxIterations 之间的所有簇数，并选择最佳的一个。在这里，maxIterations 被设置为 -1。
            //new EuclideanDistance() 表示使用欧氏距离来测量数据点之间的距离。欧氏距离是空间中两点之间的直线距离。
//            KMeansPlusPlusClusterer<DoublePoint> kMeansClusterer = new KMeansPlusPlusClusterer<>(k, 10, new EuclideanDistance(), new MersenneTwister(42));
            KMeansPlusPlusClusterer<DoublePoint> kMeansClusterer = new KMeansPlusPlusClusterer<>(k, 30, new EuclideanDistance(), new MersenneTwister(0));
            //kMeansClusterer.cluster(...) 将执行K均值聚类算法。
            //Cluster<DoublePoint>表示一个聚类
            List<CentroidCluster<DoublePoint>> clusters = kMeansClusterer.cluster(lngLatMatrix);

            double sseValue = calculateSSE(clusters);
            //存储当前k个簇数的分类结果的sse值
            sse.add(sseValue);
            numberOfClusters.add(k);
        }
    }

    /**
     * 用来计算某次分类结果的sse值
     */
    private double calculateSSE(List<CentroidCluster<DoublePoint>> clusters) {
        double sse = 0.0;
        //遍历这次分类结果
        for (CentroidCluster<DoublePoint> cluster : clusters) {
            //获取这次分类结果的当前第i个聚类的簇心
            Clusterable clusterable = cluster.getCenter();
            double[] centroid = clusterable.getPoint();
            //遍历当前聚类的points数组，里面是每一个商铺
            for (DoublePoint point : cluster.getPoints()) {
                sse += calculateDistanceSquared(point, centroid);
            }
        }
        return sse;
    }

    /**
     * 用来计算sse值中两点的经纬度的积之和
     */
    private double calculateDistanceSquared(DoublePoint point1, double[] p2) {
        double[] p1 = point1.getPoint();
        double distanceSquared = 0.0;
        //计算两点的经纬度的积之和
        for (int i = 0; i < p1.length; i++) {
            double diff = p1[i] - p2[i];
            distanceSquared += diff * diff;
        }
        return distanceSquared;
    }

    /**
     * 计算SSE下降速度的变化率，并存储在changeRate中
     */
    private List<Double> getChangeRate(List<Double> sse) {
        List<Double> changeRate = new ArrayList<>();

        if (sse.size() == 1) {
            changeRate.add(sse.get(0));
        } else {
            for (int i = 0; i < sse.size() - 1; i++) {
                changeRate.add(sse.get(i) - sse.get(i + 1));
            }
        }

        return changeRate;
    }

    /**
     * 根据changeRate和numberOfClusters得到bestK
     */
    private int getBestK(List<Integer> numberOfClusters, List<Double> changeRate) {
        int bestIndex = changeRate.indexOf(
                changeRate.stream().max(Double::compare)
                        .orElseThrow(() -> new RuntimeException("changeRate 列表为空"))
        ) + 1;

        if (numberOfClusters.size() == 1 && bestIndex == 1) {
            return numberOfClusters.get(0);
        } else {
            return numberOfClusters.get(bestIndex);
        }
    }

    /**
     * 根据beskK值进行聚类，得到bestClusters聚类结果
     */
    private List<CentroidCluster<DoublePoint>> myKmeans(int bestK, int maxIterations, int randomSeed, ArrayList<DoublePoint> lngLatMatrix) {
        RandomGenerator randomGenerator = new MersenneTwister(randomSeed);
        //使用k-means聚类算法进行分类，聚类的簇数为best_k
        KMeansPlusPlusClusterer<DoublePoint> bestClusterer = new KMeansPlusPlusClusterer<>(bestK, maxIterations, new EuclideanDistance(), randomGenerator);
        return bestClusterer.cluster(lngLatMatrix);
    }

    /**
     * 根据bestClusters聚类结果，将小聚集区保存到kmeansTempList里
     */
    private void splitClusterResultEntry(int storeNumber, int splitCount, List<CentroidCluster<DoublePoint>> bestClusters, List<double[]> clusterCenters, List<CentroidCluster<DoublePoint>> kmeansTempList, List<CentroidCluster<DoublePoint>> finalList) {
        for (int i = 0; i < splitCount; i++) {
            //得到这次分类结果里的小聚集区
            CentroidCluster<DoublePoint> doublePointCentroidCluster = bestClusters.get(i);
            //如果商铺数量满足要求，则将当前小聚集区中，距离簇心最近的商铺的经纬度保存到clusterCenters
            if (doublePointCentroidCluster.getPoints().size() <= storeNumber) {
                //得到簇心
                double[] center = doublePointCentroidCluster.getCenter().getPoint();
                //得到当前小聚集区里所有的商铺点
                List<DoublePoint> points = doublePointCentroidCluster.getPoints();
                // 初始化最小距离和最近商铺的索引
                double minDistance = Double.MAX_VALUE;
                int closestIdx = -1;

                for (int j = 0; j < points.size(); j++) {
                    DoublePoint dp = points.get(j);
                    //得到当前商铺的经纬度
                    double[] point = dp.getPoint();
                    //计算欧氏距离，即两点直线距离
                    double distance = calculateEuclideanDistance(point, center);

                    // 更新最小距离和最近商铺的索引
                    if (distance < minDistance) {
                        minDistance = distance;
                        closestIdx = j;
                    }
                }

                // 获取最近商铺的经纬度
                if (closestIdx != -1) {
                    double[] closestLngLat = points.get(closestIdx).getPoint();
                    clusterCenters.add(closestLngLat);
                }

                finalList.add(doublePointCentroidCluster);

                continue;
            }

            kmeansTempList.add(doublePointCentroidCluster);
        }
    }

    /**
     * 两点之间欧氏距离的计算方法
     */
    private double calculateEuclideanDistance(double[] point1, double[] point2) {
        double sum = 0.0;
        for (int i = 0; i < point1.length; i++) {
            sum += Math.pow(point1[i] - point2[i], 2);
        }
        return Math.sqrt(sum);
    }

    /**
     * 获取所传参数CentroidCluster聚集区转换后的lngLatMatrix
     */
    private ArrayList<DoublePoint> getLngLatMatrix(CentroidCluster<DoublePoint> centroidCluster) {
        List<DoublePoint> points = centroidCluster.getPoints();
        //直接将points传参，可以一次性将所有点的经纬度加到new ArrayList<DoublePoint>中，也就是lngLatMatrix
        return new ArrayList<>(points);
    }

    /**
     * 判断当前小聚集区的子聚集区是否有长度为0的
     */
    private int isExistRepeat(List<CentroidCluster<DoublePoint>> centroidClusters) {
        int indexOfRepeatCluster = -1;

        for (int index = 0; index < centroidClusters.size(); index++) {
            int count = 0;
            CentroidCluster<DoublePoint> cc = centroidClusters.get(index);
            List<DoublePoint> points = cc.getPoints();
            if (points.size() == 1) {
                continue;
            }

            for (int i = 0; i < 1; i++) {
                for (int j = i + 1; j < points.size(); j++) {
                    if (points.get(i).equals(points.get(j))) {
                        count++;
                    }
                }
            }
            if (count + 1 == cc.getPoints().size()) {
                indexOfRepeatCluster = index;
            }
        }
        return indexOfRepeatCluster;
    }


}
